package com.jdd.modules.parkmonthly.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jdd.common.api.vo.Result;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.system.vo.LoginUser;
import com.jdd.common.util.DateUtil;
import com.jdd.common.util.LoginUserUtils;
import com.jdd.common.util.SnowFlakeUtil;
import com.jdd.modules.configcartype.entity.ConfigCarType;
import com.jdd.modules.configcartype.service.IConfigCarTypeService;
import com.jdd.modules.parkcar.entity.ParkCarMonthly;
import com.jdd.modules.parkcar.entity.ParkSpace;
import com.jdd.modules.parkcar.service.IParkCarMonthlyService;
import com.jdd.modules.parkcar.service.IParkSpaceService;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.service.IConfigParkInfoService;
import com.jdd.modules.parking.service.IparkCarEnterLogService;
import com.jdd.modules.parkmonthly.dto.MonthlyCardDelayDto;
import com.jdd.modules.parkmonthly.entity.MonthlyCarTypeConvert;
import com.jdd.modules.parkmonthly.entity.MonthlyCardInfo;
import com.jdd.modules.parkmonthly.entity.MonthlyPackageInfo;
import com.jdd.modules.parkmonthly.service.IDelayMonthlyCardInfoService;
import com.jdd.modules.parkmonthly.service.IMonthlyCarTypeConvertService;
import com.jdd.modules.parkmonthly.service.IMonthlyCardInfoService;
import com.jdd.modules.parkmonthly.service.IMonthlyPackageInfoService;
import com.jdd.modules.sdkidentifyresultpushlog.entity.vo.ParkCarEnterLogSyncV3Vo;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogV3Service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 月卡延期
 * @Author: qilina
 * @Date: 2022-1-7
 * @Version: V2.0
 */
@Service
@Slf4j
public class DelayMonthlyCardInfoServiceImpl implements IDelayMonthlyCardInfoService {

    @Resource
    private IMonthlyCarTypeConvertService iMonthlyCarTypeConvertService;
    @Resource
    private IMonthlyPackageInfoService iMonthlyPackageInfoService;
    @Resource
    private IMonthlyCardInfoService iMonthlyCardInfoService;
    @Resource
    private IparkCarEnterLogService iparkCarEnterLogService;
    @Resource
    private IParkCarMonthlyService iParkCarMonthlyService;
    @Resource
    private IConfigCarTypeService configCarTypeService;
    @Resource
    private IParkSpaceService parkSpaceService;
    @Resource
    private IConfigParkInfoService configParkInfoService;
    @Resource
    private ISdkIdentifyResultPushLogV3Service sdkIdentifyResultPushLogV3Service;



    /**
     * 月卡延期
     *
     * @param monthlyCardDelayDto
     * @return
     */
    @Override
    @CacheEvict(value = {"monthly:cardAndPackage"}, allEntries = true)
    public Result updateMonthlyCardDelay(MonthlyCardDelayDto monthlyCardDelayDto) {

        log.info("办理月卡延期，传入参数为------------------------------》:{}", JSONObject.toJSONString(monthlyCardDelayDto));
        MonthlyCardInfo monthlyCardInfo = iMonthlyCardInfoService.getById(monthlyCardDelayDto.getMonthlyCardId());
        LoginUser loginUser = LoginUserUtils.getLoginUser();
        if (null != loginUser) {
            monthlyCardInfo.setUpdateUserId(loginUser.getUsername());
            monthlyCardInfo.setUpdateUserName(loginUser.getRealname());
        }
        MonthlyCardInfo oldMonthlyCardInfo = new MonthlyCardInfo();
        BeanUtils.copyProperties(monthlyCardInfo, oldMonthlyCardInfo);
        monthlyCardInfo.setMonthlyMoney(monthlyCardDelayDto.getMonthlyMoney());
        monthlyCardInfo.setRemark(monthlyCardDelayDto.getRemark());
        MonthlyPackageInfo packageInfo = iMonthlyPackageInfoService.getById(monthlyCardInfo.getPackageId());

        // 获取月租车信息
        boolean resFlag = true;
        List<ParkCarMonthly> parkCarMonthlys = getParkCarMonthly(monthlyCardDelayDto);
        List<String> plateNos = parkCarMonthlys.stream().map(ParkCarMonthly::getPlateNo).distinct().collect(Collectors.toList());
        List<String> areaList = parkCarMonthlys.stream().map(ParkCarMonthly::getAreaId).distinct().collect(Collectors.toList());
        // 查询绑定车位
        List<ParkSpace> parskSpace = getParkSpace(monthlyCardDelayDto);

        // 更新月租车和车位信息, 只有跳延更新开始时间
        if (packageInfo.getOverdueDelayWay() == JddConstant.IntNumber.INT_TWO) {
            parkCarMonthlys.stream().forEach(f -> f.setStartTime(monthlyCardDelayDto.getBeginTime()));
            parskSpace.stream().forEach(f -> f.setStartTime(monthlyCardDelayDto.getBeginTime()));
            monthlyCardInfo.setBeginTime(monthlyCardDelayDto.getBeginTime());
        }
        parkCarMonthlys.stream().forEach(f -> f.setEndTime(monthlyCardDelayDto.getEndTime()));
        parskSpace.stream().forEach(f -> f.setEndTime(monthlyCardDelayDto.getEndTime()));
        monthlyCardInfo.setEndTime(monthlyCardDelayDto.getEndTime());
        // 更新月卡表，更新车位表，更新月租车表，更新操作记录


        monthlyCardInfo.setUpdateTime(new Date());
        resFlag = iMonthlyCardInfoService.updateById(monthlyCardInfo);
        if (!resFlag) {
            return Result.error("更新monthlyCardInfo失败！");
        }
        resFlag = parkSpaceService.updateBatchById(parskSpace);
        if (!resFlag) {
            return Result.error("更新parskSpace失败！");
        }
        resFlag = iParkCarMonthlyService.updateBatchById(parkCarMonthlys);
        if (!resFlag) {
            return Result.error("更新parkCarMonthlys失败！");
        }
        // 新增月卡操作记录
        iMonthlyCardInfoService.getMonthlyCardEditInfo(monthlyCardInfo, JddConstant.StringNumber.STRING_TWO);
        // 是否有未占用车位
        QueryWrapper<ParkSpace> parkSpaceQueryWrapper = new QueryWrapper<>();
        parkSpaceQueryWrapper.eq("park_code", monthlyCardDelayDto.getParkCode());
        parkSpaceQueryWrapper.eq("park_status", JddConstant.StringNumber.STRING_ZERO);
        parkSpaceQueryWrapper.eq("monthly_card_id", monthlyCardInfo.getId());
        List<ParkSpace> parkSpaces = parkSpaceService.list(parkSpaceQueryWrapper);
        /*if (CollectionUtils.isEmpty(parkSpaces)) {
            return Result.ok("延期成功！");
        }*/

        // 在场车辆查询
        List<ParkCarEnterLog> parkCarEnterLogs = iMonthlyCardInfoService.getList(monthlyCardInfo.getParkCode(), plateNos, areaList);
        log.info("办理月卡延期，需要转卡的在场信息------------------------------》:{}", parkCarEnterLogs);
        if (CollectionUtil.isEmpty(parkCarEnterLogs)) {
            return Result.ok("延期成功！");
        }
        // 新增转卡
        getAddParkCarEnterLog(parkCarEnterLogs, oldMonthlyCardInfo, parkSpaces, areaList, monthlyCardInfo, packageInfo);
        return Result.ok("更新月卡信息成功！");
    }


    /**
     * 延期转卡
     *
     * @param parkCarEnterLogs
     * @param oldMonthlyCardInfo
     * @param parkSpaces
     * @param areaList
     * @param monthlyCardInfo
     * @param packageInfo
     */
    private void getAddParkCarEnterLog(List<ParkCarEnterLog> parkCarEnterLogs, MonthlyCardInfo oldMonthlyCardInfo,
                                       List<ParkSpace> parkSpaces, List<String> areaList, MonthlyCardInfo monthlyCardInfo,
                                       MonthlyPackageInfo packageInfo) {
        List<ParkCarEnterLog> parkCarEnterLogList = new ArrayList<>();
        List<MonthlyCarTypeConvert> monthlyCarTypeConverts = new ArrayList<>();
        int count = 0;
        for (ParkCarEnterLog parkCarEnterLog : parkCarEnterLogs) {
        	// 月租车入场
            if("1".equals(parkCarEnterLog.getCarNature())) {
                // 月租车入场顺延，不插入记录
                if (packageInfo.getOverdueDelayWay() == JddConstant.IntNumber.INT_ONE) {
                    continue;
                }
                // 处理跳延
                parkCarEnterLog.setId(SnowFlakeUtil.getId());
                parkCarEnterLog.setCarNature(JddConstant.StringNumber.STRING_ONE);
                parkCarEnterLog.setCarTypeName(packageInfo.getMonthlyTypeName());
                parkCarEnterLog.setCarTypeId(packageInfo.getMonthlyTypeId());
                parkCarEnterLog.setEnterType(JddConstant.IntNumber.INT_ZERO);
                parkCarEnterLog.setCreateTime(new Date());
                dealDelayLogs(monthlyCardInfo, parkCarEnterLog, oldMonthlyCardInfo, packageInfo, parkCarEnterLogList);
                MonthlyCarTypeConvert monthlyCarTypeConvert = iMonthlyCardInfoService.getMonthlyCarTypeConvert(monthlyCardInfo, parkCarEnterLog, packageInfo);
                monthlyCarTypeConverts.add(monthlyCarTypeConvert);
                continue;
            }


            // 临时车入场的车
            if ("0".equals(parkCarEnterLog.getCarNature())) {
                if (count >= parkSpaces.size()) {
                    continue;
                }
                // 临时车分配车位，无需分配车位
                count = this.dealSamePlateNoPlace(parkSpaces, parkCarEnterLog, count, areaList, monthlyCardInfo);
            }

            // 新增入场记录
            parkCarEnterLog.setId(SnowFlakeUtil.getId());
            parkCarEnterLog.setCarNature(JddConstant.StringNumber.STRING_ONE);
            parkCarEnterLog.setCarTypeName(packageInfo.getMonthlyTypeName());
            parkCarEnterLog.setCarTypeId(packageInfo.getMonthlyTypeId());
            parkCarEnterLog.setEnterType(JddConstant.IntNumber.INT_ZERO);
            parkCarEnterLog.setCreateTime(new Date());
            // 如果顺延，插入入场记录入场时间加1s，车辆类型为月租车
            if (packageInfo.getOverdueDelayWay() == JddConstant.IntNumber.INT_ONE) {
                String time = DateUtil.addSecond(parkCarEnterLog.getCarEnterTime(), JddConstant.IntNumber.INT_ONE);
                parkCarEnterLog.setCarEnterTime(time);
                parkCarEnterLog.setMonthlyCardId(monthlyCardInfo.getId());
                parkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_TWO);
                // 还原原入场记录的车位编号
                parkCarEnterLogList.add(parkCarEnterLog);
            } else {
                // 处理跳延
                dealDelayLogs(monthlyCardInfo, parkCarEnterLog, oldMonthlyCardInfo, packageInfo, parkCarEnterLogList);
                MonthlyCarTypeConvert monthlyCarTypeConvert = iMonthlyCardInfoService.getMonthlyCarTypeConvert(monthlyCardInfo, parkCarEnterLog, packageInfo);
                monthlyCarTypeConverts.add(monthlyCarTypeConvert);
            }
        }
        iMonthlyCarTypeConvertService.saveBatch(monthlyCarTypeConverts);
        if(parkCarEnterLogList.size() > 0){
        	iparkCarEnterLogService.saveBatch(parkCarEnterLogList);
        	try {
        		for(ParkCarEnterLog parkCarEnterLog : parkCarEnterLogList){
        			ParkCarEnterLogSyncV3Vo entity = new ParkCarEnterLogSyncV3Vo();
        			entity.setParkCarEnterLogStr(JSON.toJSONString(parkCarEnterLog));
        			// 月租车
					if(StringUtils.isNotBlank(parkCarEnterLog.getParkNumber())){
						entity.setParkStatus(JddConstant.ParkSpace.PARKSTATUS_ONE);
						entity.setSourceAreaId(parkCarEnterLog.getAreaId());
					}else{
						// 临时车
						entity.setParkStatus(JddConstant.ParkSpace.PARKSTATUS_ZERO);
					}
                    String url = "";
					sdkIdentifyResultPushLogV3Service.sendMessageV3(entity,url);
        		}
        	} catch (IOException e) {
        		e.printStackTrace();
        	}
        }
    }


    /**
     * 处理跳延时，在场记录的处理
     *
     * @param monthlyCardInfo
     * @param parkCarEnterLog
     * @param newMonthlyCardInfo
     */
    private void dealDelayLogs(MonthlyCardInfo newMonthlyCardInfo, ParkCarEnterLog parkCarEnterLog, MonthlyCardInfo monthlyCardInfo, MonthlyPackageInfo packageInfo, List<ParkCarEnterLog> parkCarEnterLogList) {
        // 跳延,入场时间在月卡结束时间之后，并在新月卡开始之后，新增转卡记录，月租车入场，入场时间+1s
        if (monthlyCardInfo.getEndTime().before(DateUtil.fomatDateTime(parkCarEnterLog.getCarEnterTime()))
                && newMonthlyCardInfo.getBeginTime().before(DateUtil.fomatDateTime(parkCarEnterLog.getCarEnterTime()))) {
            parkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_TWO);
            String time = DateUtil.addSecond(parkCarEnterLog.getCarEnterTime(), JddConstant.IntNumber.INT_ONE);
            parkCarEnterLog.setCarEnterTime(time);
            parkCarEnterLog.setMonthlyCardId(monthlyCardInfo.getId());
            parkCarEnterLogList.add(parkCarEnterLog);
        }
        // 跳延,入场时间在月卡结束时间之后，并在新月卡开始之前，新增欲转卡记录，月租车入场，入场时间新月租开始时间
        else if (monthlyCardInfo.getEndTime().before(DateUtil.fomatDateTime(parkCarEnterLog.getCarEnterTime()))
                && newMonthlyCardInfo.getBeginTime().after(DateUtil.fomatDateTime(parkCarEnterLog.getCarEnterTime()))) {
            parkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_ONE);
            parkCarEnterLog.setCarEnterTime(DateUtil.fomatDateTimeStr(newMonthlyCardInfo.getBeginTime()));
            parkCarEnterLog.setMonthlyCardId(monthlyCardInfo.getId());
            parkCarEnterLogList.add(parkCarEnterLog);
        }
        // 跳延,入场时间在月卡结束时间之前，插入两条记录，补一条临时车入场记录,入场时间为旧月卡结束时间，补一条月卡入场记录
        else {
            // 补临时车入场
            parkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_TWO);
            parkCarEnterLog.setCarNature(JddConstant.StringNumber.STRING_ZERO);
            parkCarEnterLog.setCarEnterTime(DateUtil.fomatDateTimeStr(monthlyCardInfo.getEndTime()));
            parkCarEnterLog.setMonthlyCardId("");
            ConfigCarType configCarType = this.getCarType(parkCarEnterLog.getParkCode(), Integer.valueOf(parkCarEnterLog.getCarTypeNo()));
            if (null != configCarType) {
                parkCarEnterLog.setCarTypeId(configCarType.getId());
                parkCarEnterLog.setCarTypeName(configCarType.getCarTypeName());
            }
            // 月租车入场记录 parkCarEnterLog;
            ParkCarEnterLog newParkCarEnterLog = new ParkCarEnterLog();
            BeanUtils.copyProperties(parkCarEnterLog, newParkCarEnterLog);
            newParkCarEnterLog.setId(SnowFlakeUtil.getId());
            newParkCarEnterLog.setCarEnterTime(DateUtil.fomatDateTimeStr(newMonthlyCardInfo.getBeginTime()));
            newParkCarEnterLog.setCarNature(JddConstant.StringNumber.STRING_ONE);
            newParkCarEnterLog.setCarTypeName(packageInfo.getMonthlyTypeName());
            newParkCarEnterLog.setMonthlyCardId(monthlyCardInfo.getId());
            newParkCarEnterLog.setCarTypeId(packageInfo.getMonthlyTypeId());
            // 今天在新月卡之前，补欲转卡（不知何时出场）
            if (new Date().before(newMonthlyCardInfo.getBeginTime())) {
                newParkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_ONE);
            } else {
                // 今天在新月卡之前，补欲转卡
                newParkCarEnterLog.setIsTransfer(JddConstant.StringNumber.STRING_TWO);
            }
            // 临时车入场不需要分配车位
            parkCarEnterLog.setParkNumber("");
            parkCarEnterLogList.add(parkCarEnterLog);
            parkCarEnterLogList.add(newParkCarEnterLog);
        }
    }


    /**
     * 获取识别类型对应的车辆类型
     */
    protected ConfigCarType getCarType(String parkCode, int type) {
        QueryWrapper<ConfigCarType> configCarTypeQueryWrapper = new QueryWrapper<>();
        configCarTypeQueryWrapper.eq("park_code", parkCode);
        List<ConfigCarType> configCarTypeList = configCarTypeService.list(configCarTypeQueryWrapper);
        for (ConfigCarType configCarType : configCarTypeList) {
            List<String> list = Arrays.asList(configCarType.getCarTypeNo().split(","));
            if (list.contains(String.valueOf(type))) {
                return configCarType;
            }
        }
        return null;
    }


    /**
     * 处理同一车牌号，多个入场记录，只分配一个车位,月租车
     *
     * @param parkSpaces
     * @param parkCarEnterLog
     * @param count
     * @param areaList
     */
    private Integer dealSamePlateNoPlace(List<ParkSpace> parkSpaces, ParkCarEnterLog parkCarEnterLog, int count, List<String> areaList, MonthlyCardInfo monthlyCardInfo) {
        ParkSpace parkSpace = parkSpaces.get(count);
        parkSpace.setPlateNo(parkCarEnterLog.getPlateNo());
        parkSpace.setMonthlyCode(monthlyCardInfo.getMonthlyCode());
        parkSpace.setMonthlyCardId(monthlyCardInfo.getId());
        parkSpace.setParkStatus("1");
        parkSpaceService.updateById(parkSpace);
        parkCarEnterLog.setParkNumber(parkSpace.getParkNumber());
        return count + 1;
    }

    /**
     * 查询月租车
     *
     * @param monthlyCardDelayDto
     * @return
     */
    private List<ParkCarMonthly> getParkCarMonthly(MonthlyCardDelayDto monthlyCardDelayDto) {
        QueryWrapper<ParkCarMonthly> parkCarMonthlyQueryWrapper = new QueryWrapper<>();
        parkCarMonthlyQueryWrapper.eq("monthly_card_id", monthlyCardDelayDto.getMonthlyCardId());
        parkCarMonthlyQueryWrapper.eq("park_code", monthlyCardDelayDto.getParkCode());
        parkCarMonthlyQueryWrapper.eq("status", "Y");
        List<ParkCarMonthly> parkCarMonthlys = iParkCarMonthlyService.list(parkCarMonthlyQueryWrapper);
        log.info("办理月卡延期，月租车信息------------------------------》:{}", parkCarMonthlys);
        return parkCarMonthlys;
    }

    /**
     * 查询车位信息
     *
     * @param monthlyCardDelayDto
     * @return
     */
    private List<ParkSpace> getParkSpace(MonthlyCardDelayDto monthlyCardDelayDto) {
        QueryWrapper<ParkSpace> parkSpaceQueryWrapper = new QueryWrapper<>();
        parkSpaceQueryWrapper.eq("park_code", monthlyCardDelayDto.getParkCode());
        parkSpaceQueryWrapper.eq("monthly_card_id", monthlyCardDelayDto.getMonthlyCardId());
        parkSpaceQueryWrapper.eq("status", "Y");
        List<ParkSpace> parskSpace = parkSpaceService.list(parkSpaceQueryWrapper);
        log.info("办理月卡延期，查询绑定车位信息------------------------------》:{}", parskSpace);
        return parskSpace;
    }


}
